import time
from abc import ABC, abstractmethod


class BaseAction(ABC):

    def __init__(self, *args, **kwds) -> None:
        # 抽象的速度信息
        self.speed = kwds.get('speed', -1)
        # 电机角度
        self.servo_angle = kwds.get('servo', [97, 30])

        # 根据电机的实际情况修改下发到电机的速度
        self.motor_rating = [1.4, 1, 1, 1]

        # 确定是否需要在运行时根据前动作更新电机角度及电机速度
        self.update_speed = False
        self.update_servo = False

        if self.speed == -1:
            self.update_speed = True

        if self.servo_angle[0] == -1 and self.servo_angle[1] == -1:
            self.update_servo = True

        self.speed_setting = self.generate_speed_setting(self.speed)
        self.fix_speed()

    def fix_speed(self):
        self.speed_setting = [int(speed * ratio) for speed, ratio in zip(self.speed_setting, self.motor_rating)]

    @staticmethod
    @abstractmethod
    def generate_speed_setting(speed, degree=0):
        pass

    def __call__(self, speed, servo_angle):
        if self.update_servo:
            self.servo_angle = servo_angle
        if self.update_speed:
            degree = 0
            if hasattr(self, 'degree'):
                degree = self.degree
            self.speed_setting = self.generate_speed_setting(speed, degree)
            self.fix_speed()

        return self.speed_setting + self.servo_angle
        
        
class Advance(BaseAction):
    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [-speed, -speed, speed, speed]
        
        
class BackUp(BaseAction):
    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [speed, speed, -speed, -speed]  
        
        
class Stop(BaseAction):

    def __init__(self, *args, **kwds):
        super().__init__(*args, **kwds)
        self.speed = 0

    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [0, 0, 0, 0]
        
        
class Sleep(BaseAction):


    def __init__(self, *args, **kwds):
        super().__init__(*args, **kwds)
        self.sleep_time = args[0]

    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return []

    def __call__(self, speed, servo_angle):
        time.sleep(self.sleep_time)
        return None
        
        
class TurnLeft(BaseAction):


    def __init__(self, *args, **kwds):
        super().__init__(*args, **kwds)
        self.degree = kwds.get('degree', 0)
        self.speed_setting = self.generate_speed_setting(speed=self.speed, degree=self.degree)
        self.fix_speed()

    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [-speed, -speed, int(speed * (1 + degree)), int(speed * (1 + degree))]
        
        
class TurnRight(BaseAction):

    def __init__(self, *args, **kwds):
        super().__init__(*args, **kwds)
        self.degree = kwds.get('degree', 0)
        self.speed_setting = self.generate_speed_setting(speed=self.speed, degree=self.degree)
        self.fix_speed()

    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [-int(speed * (1 + degree)), -int(speed * (1 + degree)), speed, speed]
        
        
class SpinClockwise(BaseAction):
    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [-speed] * 4
        
        
class SpinAntiClockwise(BaseAction):
    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [speed] * 4
        
class ShiftLeft(BaseAction):
    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [speed, -speed, -speed, speed]
        
        
class ShiftRight(BaseAction):
    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [-speed, speed, speed, -speed]
        
class LeftOblique(BaseAction):
    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [0, -speed, 0, speed]
        
        
class RightOblique(BaseAction):
    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [-speed, 0, speed, 0]        
        
        
class SetServo(BaseAction):
    def __init__(self, *args, **kwds):
        super().__init__(*args, **kwds)
        self.speed = 0

    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [0, 0, 0, 0]
        
class CustomAction(BaseAction):


    def __init__(self, *args, **kwds):
        super().__init__(*args, **kwds)
        self.speed_setting = kwds.get('motor_setting', [0, 0, 0, 0])
        self.update_controller_speed = False
        self.update_speed = False

    @staticmethod
    def generate_speed_setting(speed, degree=0):
        return [0, 0, 0, 0]